package com.yhy.wxzn.common.utils;

import com.google.common.collect.Maps;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class ListHelper {

    /**
     * 将集合根据某个属性进行分组
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TKey, TType> Map<TKey, TType> buildDictionary(List<TType> list, Function<TType, TKey> func) {

        Map<TKey, TType> map = Maps.newHashMap();

        for (TType t : list) {
            TKey value = func.apply(t);
            map.put(value, t);
        }
        return map;
    }

    /**
     * 将集合根据某个属性进行分组
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TKey, TType> Map<TKey, List<TType>> buildGroupDictionary(List<TType> list, Function<TType, TKey> func) {

        Map<TKey, List<TType>> map = Maps.newHashMap();

        for (TType t : list) {
            TKey value = func.apply(t);

            if (map.containsKey(value)) {
                map.get(value).add(t);
            } else {
                List<TType> newList = new ArrayList<TType>();
                newList.add(t);
                map.put(value, newList);
            }
        }
        return map;
    }

    /**
     * 将集合根据某个属性进行分组
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TKey, TType, TType2> Map<TKey, List<TType2>> buildGroupDictionary(List<TType> list, Function<TType, TKey> func, Function<TType, TType2> func2) {

        Map<TKey, List<TType2>> map = Maps.newHashMap();

        for (TType t : list) {
            TKey value = func.apply(t);
            if (map.containsKey(value)) {
                TType2 value2 = func2.apply(t);
                map.get(value).add(value2);
            } else {
                List<TType2> newList = new ArrayList<TType2>();
                TType2 value2 = func2.apply(t);
                newList.add(value2);
                map.put(value, newList);
            }
        }
        return map;
    }

    /**
     * 将集合根据某个属性进行排序分组(保持集合原有顺序)
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TKey, TType> Map<TKey, List<TType>> buildLinkedGroupDictionary(List<TType> list, Function<TType, TKey> func) {

        Map<TKey, List<TType>> map = Maps.newLinkedHashMap();

        for (TType t : list) {
            TKey value = func.apply(t);

            if (map.containsKey(value)) {
                map.get(value).add(t);
            } else {
                List<TType> newList = new ArrayList<TType>();
                newList.add(t);
                map.put(value, newList);
            }
        }
        return map;
    }

    /**
     * 将集合根据转换成另一个类型的集合
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <NewTType, TType> List<NewTType> select(List<TType> list, Function<TType, NewTType> func) {

        List<NewTType> result = new ArrayList<NewTType>();
        for (TType t : list) {
            NewTType value = func.apply(t);
            if (value != null) {
                result.add(value);
            }
        }

        return result;
    }

    /**
     * 将集合根据条件筛选
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TType> List<TType> where(List<TType> list, Function<TType, Boolean> func) {

        List<TType> result = new ArrayList<TType>();
        for (TType t : list) {
            Boolean value = func.apply(t);
            if (value) {
                result.add(t);
            }
        }

        return result;
    }

    /**
     * 将集合根据条件筛选第一个，如果没有满足条件的数据则返回null
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TType> TType firstOrDefault(List<TType> list, Function<TType, Boolean> func) {

        TType result = null;
        for (TType t : list) {
            Boolean value = func.apply(t);
            if (value) {
                result = t;
                break;
            }
        }

        return result;
    }

    /**
     * 将集合进行去重
     *
     * @param list
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TType> List<TType> distinct(List<TType> list) {

        HashSet<TType> hashSet = new HashSet<TType>();
        for (TType t : list) {
            hashSet.add(t);
        }

        List<TType> result = new ArrayList<TType>(hashSet);

        return result;
    }

    /**
     * 将集合进行去重
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <ProTType, TType> List<ProTType> selectAndDistinct(List<TType> list, Function<TType, ProTType> func) {

        List<ProTType> result = new ArrayList<ProTType>();
        HashSet<ProTType> hashSet = new HashSet<ProTType>();
        for (TType t : list) {
            ProTType value = func.apply(t);
            if (!hashSet.contains(value)) {
                hashSet.add(value);
                result.add(value);
            }
        }

        return result;
    }

    /**
     * 将集合按某个属性进行去重
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <ProTType, TType> List<TType> distinct(List<TType> list, Function<TType, ProTType> func) {

        List<TType> result = new ArrayList<TType>();
        HashSet<ProTType> hashSet = new HashSet<ProTType>();
        for (TType t : list) {
            ProTType value = func.apply(t);
            if (!hashSet.contains(value)) {
                hashSet.add(value);
                result.add(t);
            }
        }

        return result;
    }

    /**
     * 将集合根据选定属性求和
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TType> int sum(List<TType> list, Function<TType, Integer> func) {

        int sum = 0;
        for (TType t : list) {
            Integer value = func.apply(t);
            if (value != null) {
                sum += value;
            }
        }

        return sum;
    }

    /**
     * 将集合根据选定属性求和
     *
     * @param list
     * @param func
     * @return
     * @throws Exception
     * @author cb
     */
    public static <TType> BigDecimal sumBigDecimal(List<TType> list, Function<TType, BigDecimal> func) {

        BigDecimal sum = BigDecimal.ZERO;
        for (TType t : list) {
            BigDecimal value = func.apply(t);
            if (value != null) {
                sum = sum.add(value);
            }
        }

        return sum;
    }
}
